﻿using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Architecture;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Plumbing;
//using DTree.Style.Tools;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RevitProject.Extension
{
    internal static class ExtensionClass
    {
        readonly static double toleranceReadonly = 1e-4;
        /// <summary>
        /// 小于等于
        /// </summary>
        /// <param name="d1"></param>
        /// <param name="d2"></param>
        /// <param name="tolerance"></param>
        /// <returns></returns>
        public static bool IsLessEqExt(this double d1, double d2, double tolerance = 0.0)
        {
            if (tolerance == 0.0)
            {
                tolerance = toleranceReadonly;
            }
            double num = d2 - d1;
            return num > tolerance || Math.Abs(num) < tolerance;
        }

        /// <summary>
        /// 起点
        /// </summary>
        /// <param name="curve"></param>
        /// <returns></returns>
        public static XYZ EndPoint0(this Curve curve)
        {
            return curve.GetEndPoint(0);
        }

        /// <summary>
        /// 终点
        /// </summary>
        /// <param name="curve"></param>
        /// <returns></returns>
        public static XYZ EndPoint1(this Curve curve)
        {
            return curve.GetEndPoint(1);
        }



        /// <summary>
        /// 过滤器
        /// </summary>
        /// <typeparam name="T"> 类型</typeparam>
        /// <param name="doc"> 文档</param>
        /// <returns> list 类型</returns>
        public static IEnumerable<T> OfClass<T>(this Document doc)
            where T : Element
        {
            doc.ThrowIfNullOrInvalid();

            return new FilteredElementCollector(doc).OfClass(typeof(T)).OfType<T>();
        }

        /// <summary>
        /// 过滤器-当前视图
        /// </summary>
        /// <typeparam name="T"> 类型</typeparam>
        /// <param name="doc"> 文档</param>
        /// <param name="viewId"> 视图id</param>
        /// <returns> list 类型</returns>
        public static IEnumerable<T> OfClass<T>(this Document doc, ElementId viewId)
            where T : Element
        {
            doc.ThrowIfNullOrInvalid();
            viewId.ThrowIfNullOrInvalid();

            return new FilteredElementCollector(doc, viewId).OfClass(typeof(T)).OfType<T>();
        }

        /// <summary>
        /// 过滤器-类别
        /// </summary>
        /// <typeparam name="T"> 类型</typeparam>
        /// <param name="doc"> 文档</param>
        /// <param name="builtInCategory"> 类型</param>
        /// <returns> list类型</returns>
        public static IEnumerable<T> OfClass<T>(this Document doc, BuiltInCategory builtInCategory)
            where T : Element
        {
            doc.ThrowIfNullOrInvalid();

            return new FilteredElementCollector(doc)
                .OfClass(typeof(T))
                .OfCategory(builtInCategory)
                .OfType<T>();
        }

        public static IEnumerable<T> OfClass<T>(
            this Document doc,
            View view,
            BuiltInCategory builtInCategory
        )
            where T : Element
        {
            doc.ThrowIfNullOrInvalid();
            view.ThrowIfNullOrInvalid();

            return new FilteredElementCollector(doc, view.Id)
                .OfClass(typeof(T))
                .OfCategory(builtInCategory)
                .OfType<T>();
        }

        /// <summary>
        /// 过滤器-类别-当前视图
        /// </summary>
        /// <typeparam name="T"> 类型</typeparam>
        /// <param name="doc"> 文档</param>
        /// <param name="viewId"> 视图id</param>
        /// <param name="builtInCategory"> 类型</param>
        /// <returns> list类型</returns>
        public static IEnumerable<T> OfClass<T>(
            this Document doc,
            ElementId viewId,
            BuiltInCategory builtInCategory
        )
            where T : Element
        {
            doc.ThrowIfNullOrInvalid();
            viewId.ThrowIfNullOrInvalid();

            return new FilteredElementCollector(doc, viewId)
                .OfClass(typeof(T))
                .OfCategory(builtInCategory)
                .OfType<T>();
        }

        /// <summary>
        /// 过滤器-标高 获取指定类型的实例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="doc"></param>
        /// <param name="level"></param>
        /// <param name="builtInCategory"></param>
        /// <returns></returns>
        public static IEnumerable<T> OfClass<T>(
            this Document doc,
            Level level,
            BuiltInCategory builtInCategory
        )
            where T : Element
        {
            doc.ThrowIfNullOrInvalid();
            level.ThrowIfNullOrInvalid();

            var filter = new ElementLevelFilter(level.Id);
            return new FilteredElementCollector(doc)
                .OfClass(typeof(T))
                .OfCategory(builtInCategory)
                .WherePasses(filter)
                .OfType<T>();
        }

        public static void ThrowIfNullOrInvalid(this Element element)
        {
            if (element is null)
            {
                throw new ArgumentNullException(nameof(element));
            }
            if (!element.IsValidObject)
            {
                throw new System.ArgumentNullException(
                    nameof(element),
                    $"In Revit Element must be valid object"
                );
            }
        }

        /// <summary>
        /// 过滤器-当前视图-类别
        /// </summary>
        /// <param name="doc"> 文档</param>
        /// <param name="viewId"> 视图</param>
        /// <param name="builtInCategories"> 类型</param>
        /// <returns></returns>
        public static IEnumerable<Element> OfCategory(
            this Document doc,
            ElementId viewId,
            params BuiltInCategory[] builtInCategories
        )
        {
            doc.ThrowIfNullOrInvalid();
            viewId.ThrowIfNullOrInvalid();

            var col = new FilteredElementCollector(doc, viewId);
            return col.Where(
                item => builtInCategories.Any(o => o.Equals(item.GetBuiltInCategory()))
            );
        }


        public static BuiltInCategory GetBuiltInCategory(this Element el)
        {
            try
            {
                return el == null || el.Category == null
                    ? BuiltInCategory.INVALID
                    : (BuiltInCategory)el.Category.Id.Value;
            }
            catch
            {
                return BuiltInCategory.INVALID;
            }
        }

        public static void ThrowIfNullOrInvalid(this Document doc)
        {
            if (doc is null)
            {
                throw new ArgumentNullException(nameof(doc));
            }
            if (!doc.IsValidObject)
            {
                throw new System.ArgumentNullException(
                    nameof(doc),
                    $"In Revit Document must be valid object"
                );
            }
        }


        public static void ThrowIfNullOrInvalid(this ElementId elementId)
        {
            if (elementId is null)
            {
                throw new ArgumentNullException(nameof(elementId));
            }
            if (elementId == ElementId.InvalidElementId)
            {
                throw new System.ArgumentNullException(
                    nameof(elementId),
                    $"In Revit ElementId is ElementId.InvalidElementId"
                );
            }
        }

        public static bool IsEquals(
            this double value1,
            double value2,
            double tolerance = 1e-4
        )
        {
            return Math.Abs(value1 - value2) < tolerance;
        }


        public static bool IsEqualInDistance(this XYZ p0,
            XYZ p1,
            double tolerance = 1E-4)
        {
            try
            {
                double distance = p0.DistanceTo(p1);
                return distance <= tolerance;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 向量拍平到平面，Z值调整为0
        /// </summary>
        /// <param name="xyz"> 定位点</param>
        /// <param name="z"> Z轴坐标</param>
        /// <returns> new XYZ</returns>
        public static XYZ Flatten(this XYZ xyz, double z = 0)
        {
            return xyz == null ? default : new XYZ(xyz.X, xyz.Y, z);
        }



        /// <summary>
        /// 获取模型的定位线
        /// </summary>
        /// <param name="el"> 对象</param>
        /// <returns> 定位线</returns>
        public static Curve GetLocationCurve(this Element el)
        {
            return (el.Location as Autodesk.Revit.DB.LocationCurve)?.Curve;
        }

        /// <summary>
        /// Curve Faltten
        /// </summary>
        /// <param name="curve"></param>
        /// <param name="z"></param>
        /// <returns></returns>
        public static Curve Flatten(this Curve curve, double z = 0)
        {
            if (curve is not null)
            {
                if (curve is Line line)
                {
                    return line.Direction.IsParallel(XYZ.BasisZ) ? line : (Curve)Flatten(line, z);
                }
                else if (curve is Arc arc)
                {
                    return Flatten(arc, z);
                }
            }
            return curve;
        }

        /// <summary>
        /// 判断两个向量是否平行
        /// </summary>
        /// <param name="dir1"> 向量1</param>
        /// <param name="dir2"> 向量2</param>
        /// <param name="tolerance"> 误差</param>
        /// <returns> 是否平行</returns>
        public static bool IsParallel(
            this XYZ dir1,
            XYZ dir2,
            double tolerance = 1E-4
        )
        {
            try
            {
                return dir1 != null
                    && dir2 != null
                    && (
                        dir1.IsAlmostEqualTo(dir2, tolerance)
                        || dir1.IsAlmostEqualTo(dir2.Negate(), tolerance)
                    );
            }
            catch (Exception ex)
            {
                Console.WriteLine($"判断两个向量是否平行失败：{ex.Message}");
                return false;
            }
        }



        public static List<XYZ> GetVerts(this List<Curve> listCurve)
        {
            List<XYZ> list = new List<XYZ>();
            foreach (Curve curve in listCurve)
            {
                XYZ xyz = curve.EndPoint0();
                XYZ xyz2 = curve.EndPoint1();
                if (!list.Exists(p => p.IsAlmostEqualTo(xyz)))
                {
                    list.Add(xyz);
                }
                if (!list.Exists(p => p.IsAlmostEqualTo(xyz2)))
                {
                    list.Add(xyz2);
                }
            }
            return list;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="length"></param>
        /// <param name="tolerance"> 最小长度单位:英寸</param>
        /// <returns></returns>
        public static bool IsTolerance(
            this double length,
            double tolerance = 0.00256026455729167
        )
        {
            return length < tolerance;
        }

        public static string GetParameterValueByName(this Element el, string parameterName)
        {
            if (el is null)
            {
                return "";
            }
            var parameter = el.LookupParameterByName(parameterName);
            if (parameter is null)
            {
                return "";
            }
            return parameter.StorageType switch
            {
                StorageType.Double => parameter.AsValueString() ?? "",
                StorageType.ElementId => parameter.AsElementId().GetValue().ToString(),
                StorageType.Integer => parameter.AsValueString() ?? "",
                StorageType.String => parameter.AsString() ?? "",
                StorageType.None => parameter.AsValueString() ?? "",
                _ => "",
            };
        }


        /// <summary>
        /// 字符串转数字
        /// </summary>
        /// <param name="value"> 数字字符串</param>
        /// <returns> double </returns>
        public static double ToDouble(this string value)
        {
            try
            {
                @value = value.ToSplit(' ').ElementAtOrDefault(0);
                return Convert.ToDouble(@value);
            }
            catch
            {
                return 0.0;
            }
        }

        /// <summary>
        /// 字符串 转列表
        /// </summary>
        /// <param name="value"> str</param>
        /// <param name="sep"> 分割字符</param>
        /// <returns> str列表</returns>
        public static List<string> ToSplit(this string value, params char[] sep)
        {
            return value.IsNullOrEmpty()
                ? new List<string>()
                : value.Split(sep).Select(o => o.TrimEx()).ToList();
        }


        /// <summary>
        /// 空判断
        /// </summary>
        /// <param name="items"></param>
        /// <returns></returns>
        public static bool IsNullOrEmptyExt(this IEnumerable items)
        {
            var s = items as string;
            if (s != null)
            {
                return string.IsNullOrEmpty(s);
            }
            return items == null || items.GetCount() == 0;
        }
        /// <summary>
        /// 数量
        /// </summary>
        /// <param name="items"></param>
        /// <returns></returns>
        public static int GetCount(this IEnumerable items)
        {
            return items.Cast<object>().Count();
        }




        /// <summary>
        /// 获取管线系统类型
        /// </summary>
        /// <param name="mepCurve"></param>
        /// <returns></returns>
        public static MEPSystemType GetMEPSystemType(this MEPCurve mepCurve)
        {
            if (mepCurve is Pipe)
            {
                var id = mepCurve
                    .get_Parameter(BuiltInParameter.RBS_PIPING_SYSTEM_TYPE_PARAM)
                    .AsElementId();
                return id == null || id == ElementId.InvalidElementId
                    ? default
                    : id.ToElementType<MEPSystemType>(mepCurve.Document);
            }
            else if (mepCurve is Duct)
            {
                var id = mepCurve
                    .get_Parameter(BuiltInParameter.RBS_DUCT_SYSTEM_TYPE_PARAM)
                    .AsElementId();
                return id == null || id == ElementId.InvalidElementId
                    ? default
                    : id.ToElementType<MEPSystemType>(mepCurve.Document);
            }
            return default;
        }

        /// <summary>
        /// 非空判断
        /// </summary>
        /// <param name="items"></param>
        /// <returns></returns>
        public static bool IsNotNullEmptyExt(this IEnumerable items)
        {
            return !IsNullOrEmptyExt(items);
        }




        /// <summary>
        /// 合并相同方向相连的直线
        /// </summary>
        /// <param name="lines"></param>
        /// <returns></returns>
        public static List<Line> JoinLines(this IEnumerable<Line> lines)
        {
            var result = new List<Line>();
            var temp = new List<int>();
            for (int i = 0; i < lines.Count(); i++)
            {
                if (temp.Contains(i))
                {
                    continue;
                }

                var curve = lines.ElementAtOrDefault(i);
                var p0 = curve.GetEndPoint(0);
                var p1 = curve.GetEndPoint(1);
                for (int j = 0; j < lines.Count(); j++)
                {
                    if (i == j)
                    {
                        continue;
                    }

                    var _curve = lines.ElementAtOrDefault(j);
                    var _p0 = _curve.GetEndPoint(0);
                    var _p1 = _curve.GetEndPoint(1);
                    if (curve.Direction.HasSameDirection(_curve.Direction))
                    {
                        if (p1.HasSameDirection(_p0))
                        {
                            p1 = _p1;
                            temp.Add(j);
                        }
                        else if (p0.HasSameDirection(_p1))
                        {
                            p0 = _p0;
                            temp.Add(j);
                        }
                    }
                }
                result.Add(Line.CreateBound(p0, p1));
            }
            return result;
        }

        /// <summary>
        /// ElementId 转 ElementType
        /// </summary>
        /// <param name="id"> id</param>
        /// <param name="doc"> doc</param>
        /// <returns> el </returns>
        public static T ToElementType<T>(this ElementId id, Document doc)
            where T : ElementType
        {
            return id.ToElement(doc) as T;
        }

        /// <summary>
        /// 获取房间中心点
        /// </summary>
        /// <param name="room"> 房间</param>
        /// <param name="faltten"> 是否拍平</param>
        /// <returns> 房间中心定位点 Flatten</returns>
        public static XYZ GetCentroid(this Room room, bool faltten = true)
        {
            try
            {
                var sd = room.GetSolidBySymbol().LastOrDefault();
                var centroid = sd?.ComputeCentroid();
                return centroid != null && room.IsPointInRoom(centroid)
                    ? faltten
                        ? centroid.Flatten()
                        : centroid
                    : room.GetLocationPoint();
            }
            catch
            {
                return room.GetLocationPoint();
            }
        }


        /// <summary>
        /// 获取模型的定位点,有就返回点,没有就返回null
        /// </summary>
        /// <param name="el"> 对象</param>
        /// <returns> 定位点</returns>
        public static XYZ GetLocationPoint(this Element el)
        {
            return (el.Location as Autodesk.Revit.DB.LocationPoint)?.Point;
        }



        /// <summary>
        /// 获取模型对象的 Solid
        /// <para>用于尺寸标注</para>
        /// </summary>
        /// <param name="el"> 对象</param>
        /// <returns>按体积大小升序排列</returns>
        public static List<Solid> GetSolidBySymbol(this Element el)
        {
            var solids = new List<Solid>();
            if (el == null)
            {
                return solids;
            }
            var opt = new Autodesk.Revit.DB.Options
            {
                ComputeReferences = true,
                IncludeNonVisibleObjects = true,
            };
            foreach (var g in el.get_Geometry(opt))
            {
                if (g is GeometryInstance geometryInstance)
                {
                    foreach (var g_ins in geometryInstance.GetSymbolGeometry())
                    {
                        if (g_ins is Solid solidIns && solidIns.Volume > 0.0001)
                        {
                            solids.Add(solidIns);
                        }
                    }
                }
                else
                {
                    if (g is Solid solid && solid.Volume > 0.0001)
                    {
                        solids.Add(solid);
                    }
                }
            }
            return solids.OrderBy(o => o.Volume).ToList();
        }

        /// <summary>
        /// 点在线上垂足
        /// </summary>
        /// <param name="line"></param>
        /// <param name="pt"></param>
        /// <returns></returns>
        public static XYZ VerticalPointExt(this Line line, XYZ pt)
        {
            XYZ result = null;

            Line line1 = line.Clone() as Line;
            line1.MakeUnbound();

            IntersectionResult intersectionResult = line1.Project(pt);
            if (intersectionResult != null)
            {
                result = intersectionResult.XYZPoint;
            }
            return result;
        }


        /// <summary>
        /// IsNullOrEmpty
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool IsNullOrEmpty(this string value)
        {
            return string.IsNullOrEmpty(value);
        }

        /// <summary>
        /// 移除首尾空白字符
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string TrimEx(this string value)
        {
            return value == null ? string.Empty : value.Trim();
        }


        /// <summary>
        /// 设置管线直径
        /// </summary>
        /// <param name="pipe"></param>
        /// <param name="d"></param>
        /// <returns></returns>
        public static bool SetDiameter(this Pipe pipe, double d)
        {
            return pipe.get_Parameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM).Set(d);
        }


        public static Parameter LookupParameterByName(this Element el, string name)
        {
            try
            {
                if (el is null)
                {
                    return default;
                }

                var parameter = el.LookupParameter(name);
                if (parameter == null)
                {
                    if (name == null)
                    {
                        return default;
                    }
                    var _name = name.ToLower();
                    foreach (Parameter item in el.Parameters)
                    {
                        if (item.Definition.Name.ToLower() == _name)
                        {
                            parameter = item;
                            break;
                        }
                    }
                }
                if (parameter == null && el.IsHasElementType())
                {
                    var elementtype = el.ToElementType();
                    parameter = elementtype.LookupParameter(name);
                    if (parameter == null && elementtype != null)
                    {
                        var _name = name.ToLower();
                        foreach (Parameter item in elementtype.Parameters)
                        {
                            if (item.Definition.Name.ToLower() == _name)
                            {
                                parameter = item;
                                break;
                            }
                        }
                    }
                }
                return parameter;
            }
            catch
            {
                return default;
            }
        }


        public static ElementType ToElementType(this Element el, Document doc = null)
        {
            try
            {
                if (IsHasElementType(el))
                {
                    var thisdoc = doc ?? el.Document;
                    return el.GetTypeId().ToElement(thisdoc) as ElementType;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"ElementId:{el.Id},获取类型失败:{ex.Message}", ex);
            }
            return default;
        }

        /// <summary>
        /// ElementId 转 Element
        /// </summary>
        /// <param name="id"> id</param>
        /// <param name="doc"> doc</param>
        /// <returns> el </returns>
        public static Element ToElement(this ElementId id, Document doc)
        {
            return id == ElementId.InvalidElementId ? default : doc.GetElement(id);
        }

        public static Element ToElement(this Reference value, Document doc)
        {
            if (value is null)
            {
                return default;
            }
            var el = doc.GetElement(value);
            if (!el.IsEqualCategory(BuiltInCategory.OST_RvtLinks))
            {
                return el;
            }
            var linkInstance = el as RevitLinkInstance;
            var linkDocument = linkInstance.GetLinkDocument();
            return linkDocument?.GetElement(value.LinkedElementId);
        }

        /// <summary>
        /// 判断构件是否为指定类别模型
        /// </summary>
        /// <param name="el"> 对象</param>
        /// <param name="builtInCategory"> 类别</param>
        /// <returns> 是否相等</returns>
        public static bool IsEqualCategory(this Element el, BuiltInCategory builtInCategory)
        {
            return IsEqualCategoryId(el, (int)builtInCategory);
        }


        /// <summary>
        /// 判断构件是否为指定ID类别模型
        /// </summary>
        /// <param name="el"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        public static bool IsEqualCategoryId(this Element el, long id)
        {
            try
            {
                return el != null
                    && (el?.Category) != null
                    && el.Category != null
                    && el.Category.Id.GetValue() == id;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// 获取ID 值
        /// </summary>
        /// <param name="elementId"></param>
        /// <returns></returns>
        public static long GetValue(this ElementId elementId)
        {
            if (elementId == null)
            {
                return ElementId.InvalidElementId.GetValue();
            }
            return elementId.Value;
        }

        /// <summary>
        /// 毫米 --> 英寸
        /// </summary>
        /// <param name="value"> 毫米</param>
        /// <returns> 英寸</returns>
        public static double MMToFeet(this double value)
        {
            return value / 304.8;
        }

        public static bool IsAlmostEqualTo(
            this Curve curve0,
            Curve curve1,
            double tolerance = 1E-4
        )
        {
            try
            {
                if (curve0 == null || curve1 == null)
                {
                    return false;
                }
                var p0_0 = curve0.GetEndPoint(0);
                var p0_1 = curve0.GetEndPoint(1);
                var p1_0 = curve1.GetEndPoint(0);
                var p1_1 = curve1.GetEndPoint(1);
                return (p0_0.HasSameDirection(p1_0, tolerance) && p0_1.HasSameDirection(p1_1, tolerance))
                    || (p0_0.HasSameDirection(p1_1, tolerance) && p0_1.HasSameDirection(p1_0, tolerance));
            }
            catch
            {
                return false;
            }
        }

        public static bool HasSameDirection(
            this XYZ p0,
            XYZ p1,
            double tolerance = 1E-4
        )
        {
            try
            {
                return p0.IsAlmostEqualTo(p1, tolerance);
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 判断对象是否存在类型
        /// </summary>
        /// <param name="el"></param>
        /// <returns></returns>
        public static bool IsHasElementType(this Element el)
        {
            return el.GetTypeId() != ElementId.InvalidElementId;
        }

        public static List<ElementId> ToElementIds(this IEnumerable<Element> elements)
        {
            return elements.Where(o => o != null).Select(o => o.Id).ToList();
        }


        public static bool SetParameterByName<T>(this Element el, string name, T value)
        {
            if (el is null)
            {
                return false;
            }
            var parameter = el.LookupParameterByName(name);
            if (parameter != null && !parameter.IsReadOnly)
            {
                if (value is double para_double)
                {
                    return parameter.Set(para_double);
                }
                else if (value is int para_int)
                {
                    return parameter.Set(para_int);
                }
                else if (value is string para_string)
                {
                    return parameter.Set(para_string);
                }
                else if (value is ElementId para_ElementId)
                {
                    return parameter.Set(para_ElementId);
                }
                else
                {
                    parameter.ClearValue();
                    Console.WriteLine($"参数:{name},参数值不能为null:{nameof(value)}");
                }
            }
            return false;
        }


        /// <summary>
        /// 获取两段管线 距离最近的两个连接器
        /// </summary>
        /// <param name="cur1"> 管线1</param>
        /// <param name="cur2"> 管线2</param>
        /// <param name="connector1"> 连接器1</param>
        /// <param name="connector2"> 连接器2</param>
        /// <returns> 是否成功</returns>
        public static bool GetConnectorsByMinDistance(
            this MEPCurve cur1,
            MEPCurve cur2,
            out Connector connector1,
            out Connector connector2
        )
        {
            connector1 = connector2 = null;
            var conn1 = cur1.GetConnectors();
            var conn2 = cur2.GetConnectors();

            double minDistance = double.MaxValue;

            foreach (var c in conn1)
            {
                foreach (var d in conn2)
                {
                    var connDistance = c.Origin.DistanceTo(d.Origin);
                    if (connDistance < minDistance)
                    {
                        minDistance = connDistance;
                        connector1 = c;
                        connector2 = d;
                    }
                }
            }
            return connector1 != null && connector2 != null;
        }

        /// <summary>
        /// 通过名称获取参数值
        /// 自动测试参数(全部大写/小写)
        /// </summary>
        /// <param name="el"> 对象</param>
        /// <param name="parameterName"> 参数名称</param>
        /// <returns> string:参数名称对应的参数值.参数名称获取失败则返回:""</returns>
        public static string GetParameterValueStringByName(this Element el, string parameterName)
        {
            if (el is null)
            {
                return "";
            }
            var parameter = el.LookupParameterByName(parameterName);
            if (parameter is null)
            {
                return "";
            }
            return parameter.StorageType switch
            {
                StorageType.Double => parameter.AsValueString() ?? "",
                StorageType.ElementId => parameter.AsValueString() ?? "",
                StorageType.Integer => parameter.AsValueString() ?? "",
                StorageType.String => parameter.AsString() ?? "",
                StorageType.None => parameter.AsValueString() ?? "",
                _ => "",
            };
        }

        /// <summary>
        /// 已链接到项目
        /// </summary>
        /// <param name="revitLinkInstance"></param>
        /// <returns></returns>
        public static bool HasLinked(this RevitLinkInstance revitLinkInstance)
        {
            return revitLinkInstance?.GetLinkDocument() != null;
        }

        /// <summary>
        /// 获取所有相交线段自动打断的定位线
        /// </summary>
        /// <param name="lines"></param>
        /// <returns></returns>
        public static List<Line> GetSplitLines(this List<Line> lines)
        {
            var splitLines = new List<Line>();
            for (int i = 0; i < lines.Count; i++)
            {
                var c1 = lines[i];
                var p0 = c1.EndPoint0();
                var p1 = c1.EndPoint1();
                var temp = new List<XYZ>() { p0, p1 };
                for (int j = 0; j < lines.Count; j++)
                {
                    if (i == j)
                    {
                        continue;
                    }
                    var c2 = lines[j];
                    var p3 = c2.EndPoint0();
                    var p4 = c2.EndPoint1();
                    if (!(p0.HasSameDirection(p3) || p1.HasSameDirection(p3)) && c1.IsOnLine(p3))
                    {
                        temp.Add(p3);
                    }
                    else if (!(p0.HasSameDirection(p4) || p1.HasSameDirection(p4)) && c1.IsOnLine(p4))
                    {
                        temp.Add(p4);
                    }
                }

                var sort = temp.OrderBy(o => o.DistanceTo(p0)).ToList();
                for (int k = 0; k < sort.Count - 1; k++)
                {
                    var s = sort.ElementAt(k);
                    var e = sort.ElementAt(k + 1);

                    /// 最小长度单位:英寸
                    if (s.DistanceTo(e) <= 0.00256026455729167)
                    {
                        continue;
                    }

                    var line = Line.CreateBound(s, e);
                    splitLines.Add(line);
                }
            }
            return splitLines;
        }

        /// <summary>
        /// 判断点在直线上
        /// </summary>
        /// <param name="line"> 直线</param>
        /// <param name="xyz"> 点</param>
        /// <param name="tolor"> 误差</param>
        /// <returns> 是否</returns>
        public static bool IsOnLine(this Line line, XYZ xyz, double tolor = 1e-5)
        {
            if (xyz is null || line is null)
            {
                return false;
            }

            if (line.IsBound)
            {
                var p0 = line.GetEndPoint(0);
                var p1 = line.GetEndPoint(1);
                var legth = p0.DistanceTo(xyz) + p1.DistanceTo(xyz);
                return legth.IsEquals(line.Length, tolor);
            }
            else
            {
                return line.Project(xyz).Distance.IsEquals(0, tolor);
            }
        }



        /// <summary>
        /// 获取管线连接器列表
        /// </summary>
        /// <param name="mepcurve"></param>
        /// <param name="connectorType"></param>
        /// <returns></returns>
        public static IEnumerable<Connector> GetConnectors(this MEPCurve mepcurve)
        {
            return mepcurve.ConnectorManager.Connectors.Cast<Connector>();
        }
    }
}
